package com.wz.project.util;


import com.alibaba.fastjson.JSON;
import com.wz.project.api.sap.domain.ElementFilter;
import com.wz.project.api.sap.mapper.ElementFilterMapper;
import org.apache.velocity.anakia.NodeList;
import org.dom4j.*;
import org.dom4j.io.SAXReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import java.io.StringReader;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Component
public class XmlUtil {
    @Autowired
    private ElementFilterMapper elementFilterMapper;
    private static XmlUtil xmlUtil;


    @PostConstruct
    public void init() {
        xmlUtil = this;
        xmlUtil.elementFilterMapper = this.elementFilterMapper;

    }


    private static HashMap<String, String> xmlFiled = new HashMap<String, String>() {{
        put("diffgr:id", "id");
        put("msdata:rowOrder", "rowOrder");
        put("diffgr:hasChanges", "hasChanges");
    }};

    /**
     * 截取需要转化生成实体类的xml字符串进行转化
     *
     * @param xmlStr 需要转化的xml字符串
     * @param clazz  生成的实体类的class
     * @return
     */
    public static <T> T xmlStrToObject(String xmlStr, Class<T> clazz) {
        for (Map.Entry<String, String> entry : xmlFiled.entrySet()) {
            xmlStr = xmlStr.replaceAll(entry.getKey(), entry.getValue());
        }

        T initPointInfo = (T) checkIfWellFormed(clazz, xmlStr);
        return initPointInfo;
    }

    /**
     * 将String类型的xml转换成对象
     *
     * @param clazz
     * @param xmlStr
     * @return
     */
    private static Object checkIfWellFormed(Class clazz, String xmlStr) {
        Object xmlObject = null;
        try {
            JAXBContext context = JAXBContext.newInstance(clazz);
            Unmarshaller unmarshaller = context.createUnmarshaller();
            StringReader sr = new StringReader(xmlStr);
            xmlObject = unmarshaller.unmarshal(sr);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return xmlObject;
    }

    // 截取内容的函数
    public static String regexLabel(String xml, String label) {
        String context = "";
        //正则表达式
        String regex = "<" + label + ">(.*?)</" + label + ">";
        Pattern pattern = Pattern.compile(regex);
        Matcher m = pattern.matcher(xml);
        List<String> list = new ArrayList<String>();
        while (m.find()) {
            int i = 1;
            list.add(m.group(i));
            i++;
        }
        if (list.size() > 0) {
            context = list.get(0);
        }
        return context;
    }

    /**
     * utf-8转中文
     *
     * @param dataStr
     * @return
     */
    public static String getChinese(String dataStr) {

        if (dataStr.indexOf("&#x") != -1) {
            dataStr = dataStr.replace("&#x", "\\u");

            final StringBuffer buffer = new StringBuffer();
            String tempStr = "";
            String operStr = dataStr;
            if (!operStr.contains("\\u")) {
                System.out.println(operStr);
            }
            if (!"".equals(operStr) && !operStr.startsWith("\\u")) {
                tempStr = operStr.substring(0, operStr.indexOf("\\u"));
                operStr = operStr.substring(operStr.indexOf("\\u"), operStr
                        .length());
            }
            buffer.append(tempStr);
            while (!"".equals(operStr) && operStr.startsWith("\\u")) {
                tempStr = operStr.substring(0, 6);
                operStr = operStr.substring(7, operStr.length());
                String charStr = "";
                charStr = tempStr.substring(2, tempStr.length());
                char letter = (char) Integer.parseInt(charStr, 16);
                buffer.append(Character.toString(letter));
                if (!operStr.contains("\\u")) {
                    buffer.append(operStr);
                } else {
                    tempStr = operStr.substring(0, operStr.indexOf("\\u"));
                    operStr = operStr.substring(operStr.indexOf("\\u"), operStr
                            .length());
                    buffer.append(tempStr);
                }
            }
            return buffer.toString();
        } else {
            return dataStr;
        }
    }

    /**
     * xml字符串转实体
     *
     * @param clazz
     * @param xmlStr
     * @return
     */
    public static Object getEntity(Class clazz, String xmlStr) {
        Map<String, String> map = new HashMap<>();
        Field[] fields = clazz.getDeclaredFields();
        for (Field f : fields) {
            f.setAccessible(true);
        }
        for (Field f : fields) {
            String field = f.toString().substring(f.toString().lastIndexOf(".") + 1);
            map.put(field, getChinese(regexLabel(xmlStr, field)));
        }
        String DtoStr = JSON.toJSONString(map);
        Object o = JSON.parseObject(DtoStr, clazz);
        return o;
    }

    /**
     * xml转换为实体类list
     *
     * @param xml   要转换的xml  xml格式 <CONDITIONS><CONDITION no="" sid = "" exp = "" result = "">...</CONDITION></CONDITIONS>
     * @param clazz 实体类
     * @return
     */
    public static List resolveXmlToObjectList(String xml, Class clazz, String table, String type) throws DocumentException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        List resultList = new ArrayList();
        xml = xml.replaceAll("&#", "<![CDATA[&#]]>");
        Document document = DocumentHelper.parseText(xml);
        Element rootElement = document.getRootElement();

        List<Element> condition = rootElement.element(table).elements("item");
        if (condition != null && condition.size() > 0) {
            for (Element e : condition) {
                    Object o = clazz.newInstance();
                    List<Attribute> attributes = e.attributes();
                    if (attributes != null && attributes.size() > 0) {
                        o = getObjectByReflect(o, attributes);
                    }
                    List<Element> elements = e.elements();
                Iterator<Element> iterator = elements.iterator();
                while (iterator.hasNext()) {
                    Element e1 = iterator.next();
                    ElementFilter elementFilter = xmlUtil.elementFilterMapper.selectElementFilterById(type,e1.getQName().getName(),table);
                    if(elementFilter==null){
                        iterator.remove();
                    }
                }
                    if (elements != null && elements.size() > 0) {
                        o = getObjectByReflect(o, elements);
                    }
                    resultList.add(o);

            }
            return resultList;
        } else {
            return resultList;
        }
    }

    /**
     * 通过反射 将list里面的内容 反射到实体类中  此方法不一定共用 因为需要提前知道调用的方法，此处只是针对我的业务
     *
     * @param obj
     * @param lists
     * @return
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     */
    public static Object getObjectByReflect(Object obj, List lists) throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Object value = new Object();
        Class clazz = obj.getClass();
        for (Object $obj : lists) {
            Class<?> $clazz = $obj.getClass();
            Method getNameMethod = $clazz.getMethod("getName");
            Method getTextMethod = $clazz.getMethod("getText");
            String attributeName = (String) getNameMethod.invoke($obj);
            String attributeValue = (String) getTextMethod.invoke($obj);
            Field field = clazz.getDeclaredField(attributeName);
            field.setAccessible(true);
            Class<?> type = field.getType();
            String methodName = "set" + attributeName;
            value = getParamByType(type, attributeValue);
            Method method = clazz.getMethod(methodName, type);
            if (method != null) {
                method.invoke(obj, value);
            }
        }
        return obj;
    }

    /**
     * 根据传入参数类型  将字符串转为对应类型
     *
     * @param type  传入参数类型
     * @param value 传入字符串
     * @return
     */
    public static Object getParamByType(Class type, String value) {
        value = value.replace(" ", "");
        Object result = new Object();
        if (type == String.class) {
            result = value;
        } else if (type == int.class || type == Integer.class) {
            result = Integer.parseInt(value);
        } else if (type == float.class || type == Float.class) {
            result = Float.parseFloat(value);
        } else if (type == double.class || type == Double.class) {
            result = Double.parseDouble(value);
        } else if (type == long.class || type == Long.class) {
            result = Long.parseLong(value);
        } else if (type == short.class || type == Short.class) {
            result = Short.parseShort(value);
        } else if (type == byte.class || type == Byte.class) {
            result = Byte.parseByte(value);
        } else if (type == char.class) {
            result = value.trim().charAt(0);
        } else if (type == boolean.class || type == Boolean.class) {
            result = Boolean.parseBoolean(value);
        } else if (type == Date.class) {
            result = strToDate(value);
        } else if (type == byte[].class || type == Byte[].class) {
            result = value.getBytes();
        }
        return result;
    }

    /**
     * 将字符串转为日期
     *
     * @param value
     * @return
     */
    public static Date strToDate(String value) {
        if ("".equals(value) || value == null) {
            return null;
        }
        Date date = null;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");

        try {
            date = sdf.parse(value);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }

    /**
     * xml转换为Map类list
     *
     * @param xml
     * @return
     * @throws DocumentException
     */
    public static List resolveXmlToMapList(String xml) throws DocumentException {
        List<Map<String, String>> resultList = new ArrayList<Map<String, String>>();
        Document document = DocumentHelper.parseText(xml);
        List<Element> condition = document.getRootElement().elements("CONDITION");
        for (Element element : condition) {
            Map resultMap = new HashMap();
            List<Attribute> attributes = element.attributes();
            if (attributes != null && attributes.size() > 0) {
                for (Attribute attribute : attributes) {
                    resultMap.put(attribute.getName(), attribute.getText().replace(" ", ""));
                }
            }
            List<Element> elements = element.elements();
            if (elements != null && elements.size() > 0) {
                for (Element $element : elements) {
                    resultMap.put($element.getName(), $element.getText().replace(" ", ""));
                }
            }
            resultList.add(resultMap);
        }
        return resultList;
    }


}
